import _ from 'lodash';
import { nextTick } from 'vue'
import { ElMessage, ElLoading, ElMessageBox } from 'element-plus'
import axios from "axios";
import router from '../router'
import { isEmpty, myPrivateKey, myPublicKey, sm2DecryptStr, sm2Encrypt } from "@/utils/common";
// import { useUserStore } from '@/store/modules/user';

let loadingInstance: any; //loading 实例
let needLoadingRequestCount = 0; //当前正在请求的数量

//防抖：将 300ms 间隔内的关闭 loading 便合并为一次。防止连续请求时， loading闪烁的问题。
//因为有时会碰到在一次请求完毕后又立刻又发起一个新的请求的情况（比如删除一个表格一行后立刻进行刷新）
//这种情况会造成连续 loading 两次，并且中间有一次极短的闪烁。通过防抖可以让 300ms 间隔内的 loading 便合并为一次，避免闪烁的情况。
var hideLoading = _.debounce(() => {
  loadingInstance.close();
  loadingInstance = null;
}, 300);

function showLoading() {
  if (needLoadingRequestCount === 0 && !loadingInstance) {
    loadingInstance = ElLoading.service({
      text: '数据请求中！', background: 'rgba(0,0,0,0.3)'
    });
  }
  needLoadingRequestCount++;
}

function closeLoading() {
  nextTick(() => { // 以服务的方式调用的 Loading 需要异步关闭
    needLoadingRequestCount--;
    needLoadingRequestCount = Math.max(needLoadingRequestCount, 0); // 保证大于等于0
    if (needLoadingRequestCount === 0) {
      if (loadingInstance) {
        hideLoading()
      }
    }
  });
}

// Full config:  https://github.com/axios/axios#request-config
let config = {
  baseURL: "",
  timeout: 60 * 1000 * 10, // Timeout
  withCredentials: true, // Check cross-site Access-Control
  ctdy: true, //穿透调用
  tloading: true, //是否加载等待框
  responseType: 'json',
  header: {
    'Content-Type': 'application/json;charset=utf-8',
    post: {
      'Content-Type': 'application/json;charset=utf-8'
    },
    get: {
      'Content-Type': 'multipart/form-data'
    }
  }
};
const server = axios.create(config as any);
// @ts-ignore
const ctyd = window.WEB_CONFIG.ctdy;
// @ts-ignore
const ctdyTimeOut = window.WEB_CONFIG.ctdyTimeOut;
// @ts-ignore
const publicKey = window.WEB_CONFIG.publicKey;
// 添加请求拦截器
server.interceptors.request.use(
  function (config: any) {
    // config.headers.token = useUserStore().getToken;
    if (config.ctdy && ctyd) {
      config.headers["sys-ctdy"] = ctyd;
      config.headers["sys-timeout"] = ctdyTimeOut ? ctdyTimeOut : 2500;
    }
    if (config.tloading) {
      showLoading()
    }
    return config;
  },
  function (error) {
    closeLoading()

    // 对请求错误做些什么
    ElMessage({
      message: `错误信息：${error}!`,
      type: 'error',
      duration: 5 * 1000
    })
    return Promise.reject(error);
  }
);

// 添加响应拦截器
server.interceptors.response.use(
  function (response) {
    // 对响应数据做点什么
    closeLoading()

    let data = response.data;
    if(!response.headers){
      ElMessage({
        message: `服务没有正确返回消息头，请联系管理员!`,
        type: 'error',
        duration: 5 * 1000
      })
    }
    if (response.headers["content-type"]&&response.headers["content-type"].includes("text/plain")
    &&!response.headers["filename"]) {
      data = sm2DecryptStr(data, myPrivateKey)
    }
    if (!data.code&&response.headers["filename"]) {
      //下载文件的场景
      response.data.filename = decodeURI(response.headers["filename"]);
    }else if(data.code!==200){
      errorMessageHand(data.code, data);
      return Promise.reject(data);
    }
    return Promise.resolve(data)
  },
  function (error) {
    // 对响应错误做点什么
    closeLoading()

    let data: any = error.response.data;
    if (error.response.headers["content-type"]&&error.response.headers["content-type"].includes("text/plain")) {
      data = sm2DecryptStr(data, myPrivateKey)
    }
    if (data instanceof Blob) {
      let blob = new Blob([data]);
      blob.text().then(function (data: any) {
        data = JSON.parse(data);
        errorMessageHand(data.code, data);
        return Promise.reject(data);
      })
    } else {
      if (!data) {
        data = {
          code: error.response.status,
          msg: error.response.statusText || error.response.status
        }
      }
      errorMessageHand(data.code, data);
      return Promise.reject(data);
    }
  }
);
/**
 * 提示标志，避免重复提示
 * @type {boolean}
 */
let ts = false;
function errorMessageHand(status: any, data: any) {
  status = parseInt(status)
  switch (status) {
    case 200:
      //正常
      break
    case 403:
      // token失效
      if (!ts) {
        ts = true;
        ElMessageBox.confirm((data.msg || '该操作没有权限') + '，请确认是否拥有该权限，重新登陆试试', {
          confirmButtonText: "重新登陆",
          cancelButtonText: "取消",
          type: "error"
        }).then(() => {
          ts = false
          router.push('/login').then();
        }).catch(() => {
          ts = false
          console.log("没有权限，用户没有重新登陆");
        })
      }
      break
    default:
      // 其他错误，直接抛出错误提示
      if (!ts) {
        ts = true;
        ElMessageBox.alert(data.msg || '网络请求异常，请联系管理员', '提示', {
          confirmButtonText: 'OK',
          type: "warning",
          callback: (action: any) => {
            ts = false
          },
        }).then(function () {
          ts = false
        });
      }
  }
}
const httpHandle = {
  setToken: function (token: any) {
    server.defaults.headers['token'] = token;
  },
  setBaseURL: function (baseURL: any) {
    server.defaults.baseURL = baseURL;
    console.log("后台服务路径：" + baseURL);
  },
  getBaseURL: function (): string {
    return server.defaults.baseURL||"";
  },
  /**
   * 常规数据处理
   * @param data
   * @param config 自定义配置
   * @returns {*}
   */
  post: (data: any, config?: any) => {
    let reqData = {
      url: '/default',
      method: 'post',
      data: data, ...config
    }
    if (!isEmpty(publicKey)) {
      //如果设置了公钥则进行加密
      reqData.data.sys.publicKey = myPublicKey;
      reqData.data = sm2Encrypt(reqData.data, publicKey);
      reqData.headers = {
        'Content-Type': 'text/plain'
      }
    }
    return server(reqData)
  },
  /**
   * 上传文件
   * @param data 表单数据
   * @param config 自定义配置
   * @returns {*}
   */
  upload: (data: any, config?: any) => {
    return server({
      url: '/default',
      headers: {
        'Content-Type': 'multipart/form-data'
      },
      method: 'post',
      data: data, ...config
    })
  },
  /**
   * 下载文件
   * @param data 数据
   * @param config 自定义配置
   */
  download: (data: any, config?: any) => {
    server({
      url: '/default',
      method: 'post',
      data: data,
      responseType: 'blob', ...config
    }).then((req: any) => {
      if(!req){
        console.info("没有返回体")
        return
      }
      let blob = new Blob([req]);
      let href = URL.createObjectURL(blob);
      let event = new MouseEvent("click");
      let a = document.createElement("a");
      a.href = href;
      if (req.filename) {
        a.download = req.filename;
      } else {
        a.download = data.sys.dcwjm;
      }
      a.dispatchEvent(event);
      URL.revokeObjectURL(href);
    })
  }
}

export default httpHandle;
